package lex.util;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.LayoutManager2;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import org.lex.utils.Pair;


public class FvwmLayout implements LayoutManager2
{
	private static final int DEFAULT_CAPACITY = 4;
	static final Comparator<Pair<Component, Fvwm>> comparator = new CP();
	//====================================================
	private ArrayList<Pair<Component, Fvwm>> comps = null;
	private int componentGap = 5;
	private int leftEdgeGap = 7;
	private int rightEdgeGap = 7;

	public FvwmLayout()
	{
		this( 5, 7, 7 );
	}

	public FvwmLayout( int componentGap, int leftEdgeGap, int rightEdgeGap )
	{
		this.componentGap = componentGap;
		this.leftEdgeGap = leftEdgeGap;
		this.rightEdgeGap = rightEdgeGap;
		comps = new ArrayList<Pair<Component, Fvwm>>( DEFAULT_CAPACITY );
	}

	public int getComponentGap()
	{
		return this.componentGap;
	}

	public void setComponentGap( int componentGap )
	{
		this.componentGap = componentGap;
	}

	public int getLeftEdgeGap()
	{
		return leftEdgeGap;
	}

	public void setLeftEdgeGap( int leftEdgeGap )
	{
		this.leftEdgeGap = leftEdgeGap;
	}

	public int getRightEdgeGap()
	{
		return rightEdgeGap;
	}

	public void setRightEdgeGap( int rightEdgeGap )
	{
		this.rightEdgeGap = rightEdgeGap;
	}

	public void addLayoutComponent( String name, Component comp )
	{
		this.addLayoutComponent( comp, Fvwm.valueOf( name ) );
	}

	public void addLayoutComponent( Component comp, Object cons )
	{
		if( null == cons )
			throw new NullPointerException( "constraints cannot be null" );
		if( cons instanceof Fvwm )
			comps.add( new Pair<Component, Fvwm>( comp, (Fvwm) cons ) );
		else if( cons instanceof CharSequence )
			this.addLayoutComponent( cons.toString(), comp );
		else
			throw new IllegalArgumentException(
				"cannot add to layout: constraints must be a Fvwm" );
	}

	public void removeLayoutComponent( Component comp )
	{
		if( null == comp )
			return;
		int length = comps.size();
		for( int i = 0; i < length; i++ )
		{
			Pair<Component, Fvwm> p = comps.get( i );
			if( p.first() == comp )
			{
				comps.remove( i );
				break;
			}
		}
	}

	public float getLayoutAlignmentX( Container target )
	{
		return 0.5f;
	}

	public float getLayoutAlignmentY( Container target )
	{
		return 0.5f;
	}

	public void invalidateLayout( Container target )
	{}

	public Dimension maximumLayoutSize( Container target )
	{
		return new Dimension( Integer.MAX_VALUE, Integer.MAX_VALUE );
	}

	public Dimension minimumLayoutSize( Container parent )
	{
		return this.preferredLayoutSize( parent );
	}

	public Dimension preferredLayoutSize( Container parent )
	{
		int length = comps.size();
		int w = this.leftEdgeGap + this.rightEdgeGap;
		int h = 0;
		for( int i = 0; i < length; i++ )
		{
			Pair<Component, Fvwm> p = comps.get( i );
			Dimension size = p.first().getPreferredSize();
			w += size.width + this.componentGap;
			h = Math.max( h, size.height );
		}
		return new Dimension( w, h );
	}

	public void layoutContainer( Container parent )
	{
		//we sort the comps list before layout them
		Collections.sort( comps, comparator );
		Dimension containerSize = parent.getSize();
		int width = containerSize.width;
		int height = containerSize.height;
		int firstRightIndex = this.findFirstRightComponent();
		int x = 0;
		int y = 0;
		Dimension size = null;
		//=============== layout left part ===============
		x = this.leftEdgeGap;
		for( int i = 0; i < firstRightIndex; i++ )
		{
			Pair<Component, Fvwm> p = comps.get( i );
			Component c = p.first();
			Fvwm f = p.second();
			size = c.getPreferredSize();
			y = this.getY( f.anchor, height, size.height );
			c.setLocation( x, y );
			c.setSize( size );
			x += size.width + componentGap;
		}
		//=============== layout right part ===============
		x = width - this.rightEdgeGap;
		int componentCount = comps.size();
		for( int i = firstRightIndex; i < componentCount; i++ )
		{
			Pair<Component, Fvwm> p = comps.get( i );
			Component c = p.first();
			Fvwm f = p.second();
			size = c.getPreferredSize();
			x -= size.width;
			y = this.getY( f.anchor, height, size.height );
			c.setLocation( x, y );
			c.setSize( size );
			x -= componentGap;
		}
	}

	private int getY( int anchor, int totalHeight, int componentHeight )
	{
		switch( anchor )
		{
		case Fvwm.TOP:
			return 0;
		case Fvwm.CENTER:
			return Math.round( ((float) (totalHeight - componentHeight)) / 2 );
		case Fvwm.BOTTOM:
			return totalHeight - componentHeight;
		default:
			return 0;
		}
	}

	private int findFirstRightComponent()
	{
		int length = comps.size();
		for( int i = 0; i < length; i++ )
		{
			Pair<Component, Fvwm> p = comps.get( i );
			if( Fvwm.RIGHT == p.second().from )
				return i;
		}
		return length;
	}

	static class CP implements Comparator<Pair<Component, Fvwm>>
	{
		/**
		 * first sort using <code>from</code>, that is LEFT > RIGHT,
		 * then sort using the <code>offset</code>, lesser is bigger
		 */
		public int compare( Pair<Component, Fvwm> o1, Pair<Component, Fvwm> o2 )
		{
			Fvwm f1 = o1.second();
			Fvwm f2 = o2.second();
			if( f1.from != f2.from )
			{
				return f1.from == Fvwm.LEFT ? -1 : 1;
			}
			return f1.offset - f2.offset;
		}
	}
}
